#define _GNU_SOURCE
#include <unistd.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>

#include <stdio.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include <stdlib.h>

#include <imp/imp_log.h>

#define TAG "imp_mmap"

#define IVDC_IOBASE     0x13200000
#define ISP_IOBASE      0x13300000
#define IVPU_IOBASE     0x13100000
#define IPU_IOBASE      0x13080000

#define IVDC_SIZE       0x80000
#define ISP_SIZE        0x100000
#define IVPU_SIZE       0x100000
#define OSD_SIZE        0x10000


void *ivdc_mapbase;
int ivdc_fd = 0;

int ivdc_mmap(void)
{
	unsigned int mapped_size;
	int ret = 0;

	ivdc_fd = open("/dev/mem",  (O_RDWR | O_SYNC));
	if (ivdc_fd < 0) {
		IMP_LOG_ERR(TAG, "open /dev/mem failed\n");
		return -1;
	}

	mapped_size = IVDC_SIZE;
    if(mapped_size%getpagesize()){
        mapped_size += 0x400;
    }

    ivdc_mapbase = mmap(NULL,
					mapped_size,
					 (PROT_READ | PROT_WRITE),
					MAP_SHARED,
					ivdc_fd,
					IVDC_IOBASE);
	if (ivdc_mapbase == MAP_FAILED) {
		IMP_LOG_ERR(TAG, "mmap failed\n");
	    close(ivdc_fd);
		ret = -1;
	}

	return ret;
}

int ivdc_unmmap(void)
{
	unsigned int mapped_size;
	int ret = 0;

	if (munmap(ivdc_mapbase, IVDC_SIZE) == -1) {
		IMP_LOG_ERR(TAG, "munmap failed\n");
		ret = -1;
	}

	close(ivdc_fd);

	return ret;
}

int ivdc_regrw(unsigned int addr, unsigned int *value, unsigned int is_write)
{
	void  *virt_addr = NULL;
	unsigned int  offset_size = 0;

    if((addr<IVDC_IOBASE) || (addr>(IVDC_IOBASE+IVDC_SIZE))) {
		IMP_LOG_ERR(TAG, "addr is error\n");
        return -1;
    }
    if((ivdc_mapbase == NULL) || (ivdc_fd == 0)) {
		IMP_LOG_ERR(TAG, "should ivdc_mmap first\n");
        return -1;
    }

    offset_size = addr - IVDC_IOBASE;

	virt_addr = (char*)ivdc_mapbase + offset_size;

	if (!is_write) {
		*value = *(volatile unsigned int*)virt_addr;
    } else {
		*(volatile unsigned int*)virt_addr = *value;
    }

	return 0;
}
